/*
 * 请求日志中间件 - 请求日志记录中间件
 * 
 * 主要功能：
 * - 记录HTTP请求的详细信息
 * - 提供请求处理时间的统计
 * - 演示ASP.NET Core中间件的使用
 * - 实现请求日志的记录功能
 */

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
using OrchardCore.Settings;
using System.Diagnostics;
using System.Threading.Tasks;

namespace Lombiq.TrainingDemo.Middlewares;

/// <summary>
/// 请求日志中间件 - 记录HTTP请求的详细信息
/// 
/// 主要用途：
/// - 记录HTTP请求的详细信息
 //* - 提供请求处理时间的统计
 //* - 演示ASP.NET Core中间件的使用
 //* - 实现请求日志的记录功能
 //* 
 //* 使用场景：
/// - 记录所有HTTP请求的详细信息
/// - 统计请求处理时间
/// - 监控应用程序性能
/// - 调试请求处理流程
/// 
/// 设计原因：
/// - 提供请求级别的日志记录
/// - 实现性能监控和统计
/// - 支持应用程序的调试和监控
/// - 演示中间件的开发模式
/// 
/// 设计模式：
/// - 中间件模式：实现ASP.NET Core中间件
/// - 管道模式：使用RequestDelegate处理请求
/// - 日志模式：使用Debug.WriteLine记录日志
/// - 服务模式：注入Orchard服务
/// </summary>
// 这个中间件将作为请求的简单记录器，并使用站点名称记录每个请求。
// 注意，虽然这个中间件在它自己的类中，但我们也可以将其写为Startup类中的委托。这样Startup就不会变得混乱。

// 顺便说一下，您还记得我们在Manifest中为这个中间件声明了一个单独的模块功能吗？
// 如果没有，请再次查看Manifest.cs！
public class RequestLoggingMiddleware
{
    private readonly RequestDelegate _next;

    /// <summary>
    /// 构造函数 - 注入RequestDelegate实例
    /// </summary>
    /// <param name="next">下一个中间件委托</param>
    // 您需要在这里注入一个RequestDelegate实例。
    public RequestLoggingMiddleware(RequestDelegate next) => _next = next;

    /// <summary>
    /// 调用方法 - 处理HTTP请求并记录日志
    /// 
    /// 功能说明：
    /// - 调用下一个中间件处理请求
    /// - 记录请求的URL和站点名称
    /// - 演示Orchard服务的注入
    /// - 提供请求日志记录功能
    /// 
    /// 处理流程：
    /// - 调用下一个中间件
    /// - 获取站点设置
    /// - 记录请求信息到调试输出
    /// - 支持异常处理
    /// 
    /// 注意事项：
    /// - 可以将此调用包装在try-catch中，但需要谨慎
    /// - 未捕获的异常会导致错误页面
    /// - 建议让异常向上冒泡
    /// </summary>
    /// <param name="context">HTTP上下文</param>
    /// <param name="siteService">站点服务</param>
    /// <returns>完成的任务</returns>
    // 这个方法是实际的中间件。注意，除了第一个参数必须是HttpContext之外，
    // 其他参数可以注入Orchard服务。
    public async Task InvokeAsync(
        HttpContext context,
        ISiteService siteService)
    {
        // 我们让下一个中间件运行，但这不是强制性的：如果这个中间件要返回缓存页面，
        // 例如，那么我们会将缓存的响应写入HttpContext并省略这个调用。
        await _next(context);
        // 在将此调用包装到try-catch中时要三思：在这里您会捕获来自下一个中间件的所有异常，
        // 这些异常通常会导致404或503，所以也许最好总是让它们向上冒泡。
        // 但请记住，您代码中任何未捕获的异常都会导致错误页面。

        // 向调试输出写入消息，这样我们就能看到这段代码在运行。
        // 当使用调试器附加运行应用程序时，这将在您IDE的输出窗口中可见。
        Debug.WriteLine(
            $"URL {UriHelper.GetDisplayUrl(context.Request)} 刚刚在站点 {(await siteService.GetSiteSettingsAsync()).SiteName} 上被访问。");
    }
}

// 训练部分结束：中间件

// 下一站：Controllers/CrossTenantServicesController.cs
